package tulingxueyuan117;

import java.util.Arrays;

/**
 * Author: Zhang Dongwei
 * Date: 2022/4/5 20:25
 * 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2，另有两个整数 m 和 n ，分别表示 nums1 和 nums2 中的元素数目。
 *
 * 请你 合并 nums2 到 nums1 中，使合并后的数组同样按 非递减顺序 排列。
 *
 * 注意：最终，合并后数组不应由函数返回，而是存储在数组 nums1 中。为了应对这种情况，nums1 的初始长度为 m + n，其中前 m 个元素表示应合并的元素，后 n 个元素为 0 ，应忽略。nums2 的长度为 n 。
 *
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/merge-sorted-array
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 */
public class p8_合并两个有序数组_88 {
    public static void main(String[] args) {
        int[] num1 = {1, 2, 5, 7, 8, 89, 412, 0, 0, 0, 0, 0, 0};
        int[] num2 = {1, 3, 5, 8, 44, 124};
        merge(num1, num1.length-num2.length, num2, num2.length);
        System.out.println(Arrays.toString(num1));
    }

    // 使用内置函数，内置的函数使用的排序方法是快速排序，故时间复杂度为O((m+n)*log(m+n))
    public static void merge1(int[] nums1, int m, int[] nums2, int n) {
        for(int i = 0; i < n; i++){
            nums1[m+i] = nums2[i];
        }
        Arrays.sort(nums1);
    }

    // 双指针, 时间复杂度为O(m+n)， 时间还可以，但是占用内存比较大
    public static void merge2(int[] nums1, int m, int[] nums2, int n) {
        int[] temp = new int[m+n];
        int p1 = 0;
        int p2 = 0;
        int i = 0;
        while (i < (m + n)){
            if(p1 < m && p2 < n && nums1[p1] <= nums2[p2]){
                temp[i] = nums1[p1];
                i = i + 1;
                p1 = p1 + 1;
            }else if(p1 < m && p2 < n && nums1[p1] > nums2[p2]){
                temp[i] = nums2[p2];
                i = i + 1;
                p2 = p2 + 1;
            }else if(p1 >= m){
                temp[i] = nums2[p2];
                i = i + 1;
                p2 = p2 + 1;
            }else if(p2 >= n) {
                temp[i] = nums1[p1];
                i = i + 1;
                p1 = p1 + 1;
            }
        }
//        nums1 = temp;  // 这种方法不行，需要一个一个的赋值
        for(int k = 0; k < m + n; k++){
            nums1[k] = temp[k];
        }
    }

    // 不需要使用临时数组,利用num1最后的零元素，倒序处理, 时间复杂度为O(m+n)，空间复杂的为O(1)
    // 1.自己写的，有点问题
    public static void merge3(int[] nums1, int m, int[] nums2, int n) {
        int p1 = m - 1;
        int p2 = n - 1;
        int count = 1;
        while (count < (m + n)){
            if(p1 >= 0 && p2 >= 0 && nums1[p1] < nums2[p2]){
                nums1[m+n-count] = nums2[p2];
                count = count + 1;
                p2 = p2 - 1;
            }else if(p1 >= 0 && p2 >= 0 && nums1[p1] >= nums2[p2]){
                nums1[m+n-count] = nums1[p1];
                count = count + 1;
                p1 = p1 - 1;
            }else if(p1 <= 0){
                nums1[m+n-count] = nums2[p2];
                count = count + 1;
                p2 = p2 - 1;
            }else {
                nums1[m+n-count] = nums1[p1];
                count = count + 1;
                p1 = p1 - 1;
            }
        }
    }

    // 2.看视频解答
    public static void merge(int[] nums1, int m, int[] nums2, int n){
        int k = m + n;
        for(int index = k-1, nums1Index = m-1, nums2Index = n-1; index >= 0; index--){
            if(nums1Index < 0){  // nums1已经取完
                nums1[index] = nums2[nums2Index--];
            }else if(nums2Index < 0){  // nums2已经取完
                break;
            }else if(nums1[nums1Index] > nums2[nums2Index]){
                nums1[index] = nums1[nums1Index--];
            }else nums1[index] = nums2[nums2Index--];
        }
    }
}
